package MT::Template::Layouts;
use strict;

use base 'MT::ErrorHandler';

use vars qw( %Layouts $VERSION );
$VERSION = 0.32;

sub add_layout {
    my ($class, $tag, $layout) = @_;
    my $lctag = lc $tag;
    $Layouts{$lctag} = $layout;
    if (MT->version_number < 4) {
        require MT::Template::Context;
        MT::Template::Context->add_tag($tag => \&layout_handler);
    } else {

        # Wish I could hook the init_handlers routine in
        # MT::Template Context to include a layout type.
        # Without a good solution for MT4 we won't gripe
        # about it.
        # MT::Compat::warn();
        my $r = $MT::plugin_registry;
        $r->{tags} ||= {};
        $r->{tags}{function}{$lctag} = \&layout_handler;
    }
}

sub layout_handler {
    my ($ctx, $args, $cond) = @_;
    local $ctx->{__stash}{'MT::Plugin::TemplateLayout::args'} = $args;
    my $tag    = $ctx->stash('tag');
    my $lctag  = lc $tag;
    my $tokens = $Layouts{$lctag};
    unless (ref $tokens) {    # convert text to tokens.
        require MT::Builder;
        my $b = MT::Builder->new;
        $tokens = $b->compile($ctx, $tokens)
          or return $ctx->error($b->errstr);
        $Layouts{$lctag} = $tokens;
    }
    my $builder = $ctx->stash('builder');
    defined(my $out = $builder->build($ctx, $tokens, $cond))
      or $ctx->error("MT$tag layout error: " . $builder->errstr);
    $out;
}

1;

__END__

=head1 NAME

MT Template Layouts Toolkit - A framework for making reusable
template layouts into tags.

=head1 SYNOPSIS

 use MT::Template::Layouts;

 MT::Template::Layouts->add_layout(FeedModule => &feed);

 sub feed {
    <<TMPL
    <MTInvoke tag="MTFeed" pass_thru="uri">
    <MTInvokeContents>
        <h2><\$MTFeedTitle encode_html="1"\$></h2>
        <ul>
            <MTInvoke tag="MTFeedEntries" pass_thru="lastn offset">
            <MTInvokeContents>
            <li>
            <MTInvoke tag="FeedItemInclude" pass_thru="description"></MTInvoke>
            </li>
            </MTInvokeContents>
            </MTInvoke>
        </ul>
    </MTInvokeContents>
    </MTInvoke>
 TMPL
 }

=head1 DESCRIPTION

MT Template Layouts Toolkit is a framework for making
reusable template layouts into tags.

This began as a proof of concept with a few goals in mind:

=over

=item The ability to better reuse and distribute common
layout modules used in contructing weblog designs.

=item The ability to rapidly assemble the structure 
of a weblog

=item Cleaner more maintable modular templates.

=back 

See the L<TO DO> section for future steps and issues.

=head1 TAGS

=over

=item MTInvoke [tag="" pass_thru=""]

A container tag that creates the context for a tag to
invoke. All other tags in this module must be contained in
this one. The tag being invoked can be optional defined
using the C<tag> attribute. If a C<tag> attribute is defined
a C<MTIvokeTag> must be contained within the this tagset.

=item MTInvokeTag

A container tag that sets the name of the tag being invoked.

=item MTInvokeContents

A container tag that holds the contents of a
conditional or container tag being invoked.

=item MTInvokeSetArg name="" 

A container tag that sets the value of an attribute defined
by the C<name> attribute which is required.

=item MTLayoutArgument name=""

A variable tag that outputs the value of an argument use to
call the layout tag. The attribute C<name> is required and
defines which argument to output.

=item MTIfLayoutArgument name="" [, defined="", eq="", ne="", lt="", gt="", le="", ge=""]

A conditional tag the will build its contents if the value
of an argument used on the layout tag is true. This tag requires a
C<name> attribute that specifies the argument to compare.

To evaluate if a argument was defined (was present in the
call of the layout tag) used the C<defined> attribute with a
true value such as 1.

To evalute how an argument compares to a value the
C<MTIfLayoutArgument> tag use either C<eq>, C<ne>, C<lt>, 
C<gt>, C<le>, and C<ge> attributes passing in the value 
you want to compare. These attributes work like their Perl 
language counterpart.

    eq      equals
    ne      not equal
    lt      less than 
    gt      greater than
    le      less than equal
    ge      greater then or equal

=item MTUnlessLayoutArgument name="" [, defined="", eq="", ne="", lt="", gt="", le="", ge=""]

A conditional tag the will build its contents if the value
of an argument used on the layout tag is false. This tag performs 
the opposite operation of C<MTIfLayoutArgument> with all the same 
attributes.

=back

=head1 TO DO

=over

=item Can read in layouts from files. YAML isn't terribly
good with long string values.

=item Library of common (and not so common) layouts. MT3 and
MT4?

=item MT4: Introduction of the "layout:" prefix

=item Integration with the WidgetManager?

=item MT4: Registry integration. Deprecate add_layout
method.

=item MT4: Template snippets integration

=item What should the scope of layout token cache be? system
or request? Currently system.

=item Is error handling sufficient?

=back

=head1 AUTHOR & COPYRIGHT

Copyright 2006-2007, Timothy Appnel, Appnel Internet
Solutions, LLC. http://appnel.com/

This program is free software; you can use, modify, and
redistribute it under the same terms as Perl 5.8.x itself.

See http://www.perl.com/perl/misc/Artistic.html

=cut
